﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AForge.Imaging;
using System.Drawing;
using AForge.Imaging.Filters;
using System.Threading;
using System.Drawing.Imaging;
using BrainTechLLC.FilterExtensions;
using BrainTechLLC.ImageOperators;
using BrainTechLLC.ImageOperatorsNonAForgeDependent;

namespace TemporalFilterExtensions
{
    [Serializable]
    public class DifferenceFilterCompareTwo : SingleFilterBase, ITemporalFilterNoState, IFilter, ISingleFilter
    {
        [NonSerialized]
        protected Difference _filterDifference;

        [NonSerialized]
        protected Bitmap _lastBitmap;

        public new Difference Filter
        {
            get
            {
                if (_filterDifference == null)
                    Interlocked.CompareExchange<Difference>(ref _filterDifference, new Difference(), null);

                return _filterDifference;
            }
        }

        public Bitmap Apply(Bitmap bm1, Bitmap bm2)
        {
            try
            {
                BitmapData bmData = bm1.LockBits(new Rectangle(Point.Empty, bm1.Size), ImageLockMode.ReadOnly, bm1.PixelFormat);

                try
                {
                    return Apply(bmData, bm2);
                }
                finally
                {
                    bm1.UnlockBits(bmData);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return null;
            }
        }

        protected Bitmap Apply(BitmapData bmData, Bitmap bm2)
        {            
            Filter.OverlayImage = bm2;
            Bitmap result = Filter.Apply(bmData);
            return result;
        }

        protected bool BeforeApply(Bitmap bm)
        {
            if (_lastBitmap == null)
            {
                _lastBitmap = bm.Clone() as Bitmap;
                return true;
            }

            return false;
        }

        protected bool BeforeApply(UnmanagedImage img)
        {
            if (_lastBitmap == null)
            {
                _lastBitmap = img.ToManagedImage().Clone() as Bitmap;
                return true;
            }

            return false;
        }

        protected void AfterApply(Bitmap bm, bool firstTime)
        {
            if (!firstTime)
            {
                if (_lastBitmap != null)
                {
                    _lastBitmap.Dispose();
                    _lastBitmap = null;
                }
                _lastBitmap = bm.Clone() as Bitmap;
            }
        }

        protected void AfterApply(UnmanagedImage img, bool firstTime)
        {
            if (!firstTime)
            {
                if (_lastBitmap != null)
                {
                    _lastBitmap.Dispose();
                    _lastBitmap = null;
                }
                _lastBitmap = img.ToManagedImage().Clone() as Bitmap;
            }
        }

        public Bitmap Apply(Bitmap image)
        {
            return Apply(string.Empty, image);
        }

        public Bitmap Apply(string fileName, Bitmap image)
        {            
            OnBeforeFilterBitmap(image, Name, fileName, this);
            bool firstTime = BeforeApply(image);
            
            Bitmap result = Apply(image, _lastBitmap);

            AfterApply(image, firstTime);
            OnAfterFilterBitmap(result, Name, fileName, this);
            return result;
        }

        
        public override Bitmap Apply(string fileName, Bitmap bmp, bool returnCopyIfNoAction, bool wantPostProcessInfo, ref List<RGBAndCoordinate> postProcessInfo, ref int width, ref int height)
        {
            if (Disabled)
            {
                return bmp.CloneIfTrue(returnCopyIfNoAction);                
            }

            return Apply(fileName, bmp);
        }

        public override Bitmap Apply(string fileName, BitmapData imageData, bool wantPostProcessInfo, ref List<RGBAndCoordinate> postProcessInfo, ref int width, ref int height)
        {
            throw new NotImplementedException();
        }

        public override Bitmap Apply(string fileName, Bitmap bm, bool returnCopyIfNoAction)
        {
            return Apply(fileName, bm);
        }

        public override UnmanagedImage Apply(string fileName, UnmanagedImage image, bool wantPostProcessInfo, ref List<RGBAndCoordinate> postProcessInfo, ref int width, ref int height)
        {
            bool firstTime = BeforeApply(image);

            if (_lastBitmap.Size.Width != image.Width || _lastBitmap.Size.Height != image.Height)
            {
                _lastBitmap.Dispose();
                _lastBitmap = null;
                _lastBitmap = image.ToManagedImage().Clone() as Bitmap;
            }

            Filter.OverlayImage = _lastBitmap;
            var result = Filter.Apply(image);

            AfterApply(image, firstTime);            
            return result;
        }

        public override string Name
        {
            get { return "Diff filter"; }
        }

        public List<PixelFormat> GetValidPixelFormats()
        {
            return Filter.GetValidPixelFormats();
        }

        public bool IsValidPixelFormat(PixelFormat pixelForm)
        {
            return Filter.IsValidPixelFormat(pixelForm);
        }

        public Bitmap Apply(BitmapData imageData)
        {
            return Filter.Apply(imageData);
        }

        public UnmanagedImage Apply(UnmanagedImage image)
        {
            return Filter.Apply(image);
        }

        public void Apply(UnmanagedImage sourceImage, UnmanagedImage destinationImage)
        {
            Filter.Apply(sourceImage, destinationImage);
        }
    }
}
